package com.hyxt.handler;

import com.alibaba.dubbo.config.annotation.Reference;
import com.hyxt.DO.pojo.PlatInfo;
import com.hyxt.DTO.CommonMessage;
import com.hyxt.DTO.PlatConfig;
import com.hyxt.DTO.PlatLinks;
import com.hyxt.DTO.T809_MessageHeader;
import com.hyxt.DTO.protocol.JTBZF_0x03;
import com.hyxt.DTO.protocol.ProtocolUtil;
import com.hyxt.api.ChainLinkServer;
import com.hyxt.api.ILinkService;
import com.hyxt.service.IReceiveMsg;
import com.hyxt.superviseservice.messageBody.T809_0x9001;
import com.hyxt.utils.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author songm
 * @version v1.0
 * @Description 主链路服务端数据处理类
 * @Date: Create in 21:33 2017/12/19
 * @Modifide By:
 **/

public class ServerHandler extends SingleListenerHandler {

    private static final Log log = LogFactory.getLog(ServerHandler.class);

    //监听809从链路接口
    private IReceiveMsg receiveMsg;

    private ILinkService linkService;

    private T809_ProtocolAnalysis analysis = new T809_ProtocolAnalysis();

    //心跳定时任务
    private Timer timer;

    //    private PlatLinks platLinks = (PlatLinks) Caches.platLinks.get(getPlatId());
    private PlatLinks platLinks;
    //平台id
    private String platId;

    //平台配置文件
    private PlatConfig platConfig;

    //主链路通道名
    private String mainChannel;

    //809链路管理
    @Reference(version = "1.0.0")
    private ChainLinkServer chainLinkServer;

    public ServerHandler() {
//        platLinks = (PlatLinks) Caches.platLinks.get(getPlatId());
    }

    public String getPlatId() {
        return platId;
    }

    public ServerHandler(String mainChannel) {
        this.mainChannel = mainChannel;
    }

    public void setPlatId(String platId) {
        this.platId = platId;
    }

    public PlatConfig getPlatConfig() {
        return platConfig;
    }

    public String getMainChannel() {
        return mainChannel;
    }

    public void setMainChannel(String mainChannel) {
        this.mainChannel = mainChannel;
    }

    public void setPlatConfig(PlatConfig platConfig) {
        this.platConfig = platConfig;
    }

    @Override
    public void process(String redisData) {
        //链路创建或销毁的消息
        String linkMag = redisData;
        String type = linkMag.split(":")[0];
        //如果是创建链路
        if ("channelActive".equalsIgnoreCase(type)) {

            //如果是销毁链路
        } else if ("channelInactive".equalsIgnoreCase(type)) {

        } else {
            byte[] data = redisData.getBytes();
            byte[] data_reverse = new byte[0];
            try {
                data_reverse = T809_Util.reverseEscapeData(data);
            } catch (ProtocolEscapeExeption protocolEscapeExeption) {
                protocolEscapeExeption.printStackTrace();
            }
            int messageID = T809_Util.getMessageID(data_reverse, null);

            if (data_reverse[9] == 0x10 && data_reverse[10] == 0x01) {
                // 1001登录请求
                mainChannelResponseLogin();
                subChannelRequestLogin();
                Uplink809Command(12, messageID, data_reverse);
            } else if (data_reverse[9] == 0x10 && data_reverse[10] == 0x03) {// receive
                mainChannelResponseClose();
            } else if (data_reverse[9] == 0x10 && data_reverse[10] == 0x05) {// receive
                mainChannelResponseBeat();
                Uplink809Command(12, messageID, data_reverse);
            } else {
                if (platId.equals("510000")) {
                    if (messageID == 0x1202) {
                        int hour = Integer.valueOf(new SimpleDateFormat("HH").format(new Date()));
                        if (6 <= hour && hour < 22) {
                            byte[] a = BytesUtil.int2bytes2(80);
                            data_reverse[77] = a[0];
                            data_reverse[78] = a[1];
                        } else {
                            byte[] a = BytesUtil.int2bytes2(80);
                            data_reverse[77] = a[0];
                            data_reverse[78] = a[1];
                        }
                        System.out.println("1202-----");
                    }
                }
                Uplink809Command(12, messageID, data_reverse);
            }
        }
    }

    /**
     * 主链路应答2.0登录请求
     */
    public void mainChannelResponseLogin() {
        byte[] data = U809.es(U809.changeCode(BytesUtil.toStringHex("5b0000001f0000000010020000c4e1010000000000000000000004d2c8705d"), Integer.parseInt(platConfig.getAcceptCode())));
        // response 0x1002
        //Connection.serverChannel.writeAndFlush(data);
        //将主链路连接状态存入map
        if (platLinks == null) {
            platLinks = new PlatLinks();
            platLinks.setMainChannel(mainChannel);
        } else {
            platLinks.setMainChannel(mainChannel);
        }
        //调用链路管理接口通过主链发送响应消息
        chainLinkServer.sendMsg(mainChannel, new String(data));

        log.debug(">>>809主链路发送信息:" + BytesUtil.bytesToHexString(data));
    }

    /**
     * 2.0请求登录后创建从链路
     */
    private void subChannelRequestLogin0() {

        //String[] add = String.valueOf(config.get("clientAddress")).split(":");

        T809_MessageHeader header = new T809_MessageHeader();
        T809_0x9001 body9001 = new T809_0x9001();
        header.setMessageID(0x9001);
        header.setGnsscentrid(Integer.parseInt(platConfig.getAcceptCode()));
        body9001.setMessageID(0x9001);
        CommonMessage<T809_0x9001> message = new CommonMessage<T809_0x9001>(0x9001, header, body9001);
        header.setVersonFlag(new byte[]{1, 0, 0});
        // pack 0x9001 message
        byte[] data = analysis.pack(message);
        //todo 创建从链路
        linkService = ApplicationContextUtil.getBean(ILinkService.class);
        String subChannelName = linkService.connectVMS(platId, platConfig.getSlaveLinkIp(), platConfig.getSlaveLinkPort());
        //如果创建成功
        if (subChannelName != null) {
            //将从链路连接状态存入map
            platLinks.setSlaveChannel(subChannelName);
            //通知从链路监听通道消息
            SlaveHandler slaveHandler = new SlaveHandler();
            slaveHandler.setPlatId(platId);
            slaveHandler.setPlatConfig(platConfig);
            Caches.clientHandlers.put(subChannelName, slaveHandler);
            receiveMsg = (IReceiveMsg) ApplicationContextUtil.getBean("receive809ClientMsg");
            receiveMsg.listen(subChannelName);

            //todo 通过创建的从链路发送登录请求消息
            chainLinkServer.sendMsg(subChannelName, new String(data));
            //Connection.clientChannel.writeAndFlush(data);
            log.debug(">>>809从链路发送信息:" + BytesUtil.bytesToHexString(data));
        }
    }

    /**
     * 从链路心跳
     */
    public void subChannelRequestBeat() {
        byte[] data = U809.es(U809.changeCode(BytesUtil.toStringHex("5b0000001a0000463c900500e508e900000000000004d267855d"), Integer.parseInt(platConfig.getAcceptCode())));
        // send 0x9005 beatheat data
        // 调用链路管理接口发送消息
        String slaveChannel = platLinks.getSlaveChannel();
        chainLinkServer.sendMsg(slaveChannel, new String(data));
        //Connection.clientChannel.writeAndFlush(data);
        log.debug(">>>809从链路发送信息:" + BytesUtil.bytesToHexString(data));
    }

    /**
     * 创建从链路
     */
    public void subChannelRequestLogin() {
        // sub channel try to connect and login
        subChannelRequestLogin0();
        // timer task to check sub channel whether it is connected
        if (timer == null) {
            timer = new Timer();
        } else {
            timer.cancel();
            timer = new Timer();
        }
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                try {
                    if (null != platLinks.getSlaveChannel()) {
                        //如果从链路创建成功发送心跳消息
                        subChannelRequestBeat();
                    } else {
                        subChannelRequestLogin0();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }, 60 * 1000, 60 * 1000);

    }

    /**
     * 上行809指令(0x03)
     *
     * @param uid
     * @param messageID
     * @param command
     */
    public void Uplink809Command(int uid, int messageID, byte[] command) {
        JTBZF_0x03 body_0x03 = new JTBZF_0x03();
        // 这个位置 应该有一个<车牌号+颜色,List<企业ID>>
        //主动上报报警处理结果信息
        if (messageID == 0x1403) {
            log.info("1403!!!!!!!!!");
        }
        Set keySet = Caches.accessCodeToBusinessCache.keySet();
        if (platConfig.getCommandList().contains(messageID + "")) {
            // 这样的话说明是车辆类指令业务[先解析出车牌号,然后拿到所有车牌对应的平台]
            // 1601、1501、1502、1503、1504、1505、1401、1402、1201、
            // 1202、1203、1205、1206、1207、1208、1209、120A、120B、120C、120D
            // 车牌号
            byte[] plateNumber = BytesUtil.cutBytes(23, 21, command);
            // 车牌颜色
            byte color = BytesUtil.cutBytes(44, 1, command)[0];
            // 车牌号+车牌颜色唯一标识
            String key = "";
            try {
                key = new String(plateNumber, "GBK").trim() + color;
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            // System.out.println(key);

            //todo 通过车辆获取到平台列表（去查数据库吧）
            //List<Integer> businesseList = (List<Integer>) ((Map) config.get("vehiclePlat")).get(key);
            List<Integer> businesseList = null;

            log.debug("key:" + key + " plats:" + businesseList + " whileList:");
            // 遍历所有平台进行转发(因为一个车对应的平台很多,平台ID不一样,需要遍历车对应的每一个平台,改了平台ID,再发)
            //上面的注释是设计系统的构想,实际情况白名单只有一个
            if (businesseList != null) {
                for (int businessID : businesseList) {
                    // log.info("id"+businessID+":"+key);
                    if (!(Arrays.asList(platConfig.getWhiteList().split(",")).contains(businessID + ""))) {
                        continue;
                    }
                    // log.info("ok:" + key);
                    byte[] messageID_bytes = BytesUtil.int2bytes2(messageID);
                    //交通部协议中规定的是车辆类指令是车辆唯一标识,非车辆类指令是平台id,后来全都改成了平台id
                    body_0x03.setUid(businessID);// 平台id
                    body_0x03.setBusiness(messageID_bytes);// 消息id

                    String aaa = null;
                    // 通过平台id获取接入码，然后把原消息接入码替换掉
                    for (Object object : keySet) {
                        if (Caches.accessCodeToBusinessCache.get(object).equals(businessID + "")) {
                            command = U809.changeCode(command, Integer.valueOf((String) object));
                            aaa = (String) object;
                            break;
                        }
                    }
                    final JTBZF_0x03 bodyfinal = body_0x03;
                    final byte[] commandfinal = command;
                    final String aaafinal = aaa;
//
                    body_0x03.setBytes_809(U809.es(command));
                    // 判断各平台是否连接成功，以此依据发送数据
                    if (aaa != null) {
                        // 得到打包的消息
                        final byte[] message = ProtocolUtil.getMessageByBody((byte) 0x03, body_0x03);
                        // log.info("准备发送:"+key);
                        // 调用链路管理接口，通过转发链路发送消息
                        chainLinkServer.sendMsg(platLinks.getTransferChannel(), new String(message));
                        /*transferChannel.writeAndFlush(message).addListener(new ChannelFutureListener() {

                            @Override
                            public void operationComplete(ChannelFuture future) throws Exception {

                                if (future.isSuccess()) {
                                    // 这就是发送成功
                                    saveLimitedCatch(message);
                                    log.info(">>>交通部转发平台链路发送信息:" + BytesUtil.bytesToHexString(message));
                                } else {
                                    // 这个位置推送前台 TODO
                                }
                            }
                        });*/
                    }
                }
            }

        } else if (messageID == 0x1001 || messageID == 0x1003 || messageID == 0x1005) {
            for (Object object : keySet) {
                final int businessID = Integer.valueOf((String) Caches.accessCodeToBusinessCache.get(object));
                final byte[] messageID_bytes = BytesUtil.int2bytes2(messageID);
                body_0x03.setUid(businessID);
                body_0x03.setBusiness(messageID_bytes);

                if (!(Arrays.asList(platConfig.getWhiteList().split(",")).contains(businessID + ""))) {
                    continue;
                }
                if (messageID == 0x1001) {
                    Dao dao = new Dao();
                    PlatInfo info = dao.selectPlatByCode(object.toString());
                    byte[] userid = BytesUtil.int2bytes4(info.getUserid());
                    byte[] pass = BytesUtil.writeStrToAppoint(info.getPassword(), 8);
                    // byte[] ip =
                    // BytesUtil.writeStrToAppoint("219.143.235.110", 32);

                    byte[] ip = BytesUtil.writeStrToAppoint(platConfig.getTransportMgtIp(), 32);
                    // 219.143.235.110
                    // 111.205.202.82
                    byte[] port = BytesUtil.int2bytes2(platConfig.getTransportMgtPort());
                    command[23] = userid[3];
                    command[24] = userid[2];
                    command[25] = userid[1];
                    command[26] = userid[0];
                    System.arraycopy(pass, 0, command, 27, pass.length);
                    System.arraycopy(ip, 0, command, 35, ip.length);
                    command[67] = port[0];
                    command[68] = port[1];
                    command = U809.changeCode(command, Integer.valueOf((String) object));

                    body_0x03.setBytes_809(U809.es(command));

                    // 得到打包的消息
                    final byte[] message = ProtocolUtil.getMessageByBody((byte) 0x03, body_0x03);

                    //调用链路管理接口，通过转发链路发送消息
                    chainLinkServer.sendMsg(platLinks.getTransferChannel(), new String(message));
                    /*transferChannel.writeAndFlush(message).addListener(new ChannelFutureListener() {

                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {

                            if (future.isSuccess()) {
                                // 这就是发送成功
                                saveLimitedCatch(message);
                                log.info(">>>交通部转发平台链路发送信息:" + BytesUtil.bytesToHexString(message));

                            } else {
                                // 这个位置推送前台 TODO
                            }
                        }
                    });*/

                } else if (messageID == 0x1003) {
                    Dao dao = new Dao();
                    PlatInfo info = dao.selectPlatByCode(object.toString());
                    byte[] userid = BytesUtil.int2bytes4(info.getUserid());
                    byte[] pass = BytesUtil.writeStrToAppoint(info.getPassword(), 8);
                    command[23] = userid[3];
                    command[24] = userid[2];
                    command[25] = userid[1];
                    command[26] = userid[0];
                    System.arraycopy(pass, 0, command, 27, pass.length);
                    command = U809.changeCode(command, Integer.valueOf((String) object));
                    body_0x03.setBytes_809(U809.es(command));

                    // 得到打包的消息
                    final byte[] message = ProtocolUtil.getMessageByBody((byte) 0x03, body_0x03);
                    //调用链路管理接口，通过转发链路发送消息
                    chainLinkServer.sendMsg(platLinks.getTransferChannel(), new String(message));
                    /*transferChannel.writeAndFlush(message).addListener(new ChannelFutureListener() {

                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {

                            if (future.isSuccess()) {
                                // 这就是发送成功
                                saveLimitedCatch(message);
                                log.info(">>>交通部转发平台链路发送信息:" + BytesUtil.bytesToHexString(message));
                            } else {
                                // 这个位置推送前台 TODO
                            }
                        }
                    });*/
                } else {

                    command = U809.changeCode(command, Integer.valueOf((String) object));

                    body_0x03.setBytes_809(U809.es(command));

                    // 得到打包的消息
                    final byte[] message = ProtocolUtil.getMessageByBody((byte) 0x03, body_0x03);
                    //调用链路管理接口，通过转发链路发送消息
                    chainLinkServer.sendMsg(platLinks.getTransferChannel(), new String(message));
                    /*transferChannel.writeAndFlush(message).addListener(new ChannelFutureListener() {

                        @Override
                        public void operationComplete(ChannelFuture future) throws Exception {

                            if (future.isSuccess()) {
                                // 这就是发送成功
                                saveLimitedCatch(message);
                                log.info(">>>交通部转发平台链路发送信息:" + BytesUtil.bytesToHexString(message));
                            } else {
                                // 这个位置推送前台 TODO
                            }
                        }
                    });*/
                }
            }
        } else {
            // 非车辆指令信息 采用平台唯一编号 这个时候呢 要去找流水号-->接入码-->企业ID
            //809指令中的报文序列号就是交通部协议中的流水号
            byte[] seq809_bytes = BytesUtil.cutBytes(5, 4, command);
            // 得到流水号
            int seq = BytesUtil.bytes2int4(seq809_bytes);
            // 获得接入码

            int accessCode = 0;
            if (messageID == 0x1301 || messageID == 0x1401) {
                //平台查岗应答  报警督办应答
                // System.out.println("!!!!!!!!!"+seq);
                // String a = (String) pcache.remove(seq + "");
                // String[] b = a.split(":");
                // accessCode = Integer.valueOf(b[0]).intValue();
                // SnapshotUtil.createSnapshot(pcache);
                accessCode = U809.getAccessCode(command);
            } else {
                try {
                    accessCode = U809.getAccessCode(command);
                } catch (Exception e) {
                    e.initCause(new Exception(BytesUtil.bytesToHexString(command)));
                    e.printStackTrace();
                    accessCode = U809.getAccessCode(command);
                }

            }
            // 拿到企业ID
            int businessID = Integer.valueOf(platId);

            // 收拾收拾发送
            byte[] messageID_bytes = BytesUtil.int2bytes2(messageID);
            if (!(Arrays.asList(platConfig.getWhiteList().split(",")).contains(businessID + ""))) {
                return;
            }
            body_0x03.setUid(businessID);
            body_0x03.setBusiness(messageID_bytes);
            command = U809.changeCode(command, accessCode);
            body_0x03.setBytes_809(U809.es(command));

            // 得到打包的消息
            final byte[] message = ProtocolUtil.getMessageByBody((byte) 0x03, body_0x03);

            //调用链路管理接口，通过转发链路发送消息
            chainLinkServer.sendMsg(platLinks.getTransferChannel(), new String(message));
            /*transferChannel.writeAndFlush(message).addListener(new ChannelFutureListener() {

                @Override
                public void operationComplete(ChannelFuture future) throws Exception {

                    if (future.isSuccess()) {
                        // 这就是发送成功
                        saveLimitedCatch(message);
                        log.info(">>>交通部转发平台链路发送信息:" + BytesUtil.bytesToHexString(message));
                    } else {
                        // 这个位置推送前台 TODO
                    }
                }
            });*/

        }
    }

    /**
     * 主链路响应2.0发送的心跳消息
     */
    public void mainChannelResponseBeat() {
        byte[] data = U809.es(U809.changeCode(BytesUtil.toStringHex("5b0000001a00003482100600e508e900000000000004d220a35d"), Integer.parseInt(platConfig.getAcceptCode())));
        // response 0x1006
        // 调用链路管理接口发送消息
        chainLinkServer.sendMsg(mainChannel, new String(data));
        //Connection.serverChannel.writeAndFlush(data);
        log.debug(">>>809主链路发送信息:" + BytesUtil.bytesToHexString(data));
    }

    /**
     * 主链路响应2.0发送的关闭链路消息
     */
    public void mainChannelResponseClose() {
        byte[] data = U809.es(U809.changeCode(BytesUtil.toStringHex("5b0000001a00003482100400e508e900000000000004d2aa655d"), Integer.parseInt(platConfig.getAcceptCode())));
        //Connection.serverChannel.writeAndFlush(data).sync();
        //调用链路管理接口，通过从链路发送响应消息
        String slaveChannel = platLinks.getSlaveChannel();
        chainLinkServer.sendMsg(slaveChannel, new String(data));
        //调用链路管理接口，关闭从链路
        int integer = chainLinkServer.closeChannel(slaveChannel);
        //返回值为0代码关闭成功
        if (integer == 0) {
            //移除从链路连接状态
            platLinks.setSlaveChannel(null);
            //移除主链路连接状态
            platLinks.setMainChannel(null);
            //删除从链路心跳定时任务
            if (timer != null) {
                timer.cancel();
                timer = null;
            }
        }
    }
}
